package cn.yitun.chat.yitunserverrunsingleboot.chat.common.app;

import cn.yitun.chat.yituncommonlibutil.lib.YitunJsonUtil;
import cn.yitun.chat.yituncommonmessage.ExceptionEnum;
import cn.yitun.chat.yituncommonmessage.YitunException;
import cn.yitun.chat.yitunservercommonlib.exception.ErrorResultMessage;
import cn.yitun.chat.yitunservermanagecore.util.ResponseUtil;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;

/**
 * 类描述：异常捕获
 * @author chenyitun
 * @version 1.1
 */
@Component
@Slf4j
public class ExceptionResolver implements HandlerExceptionResolver {


	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
		ex.printStackTrace();
		StackTraceElement[] array = ex.getStackTrace();
		StringBuilder exception = new StringBuilder();
		if (null != array) {
			for (StackTraceElement stackTraceElement : array) {
				exception.append(stackTraceElement);
				exception.append("\n");
			}
		}
		if (log.isDebugEnabled())
			log.error(ex.getMessage(), ex);

		ErrorResultMessage result = new ErrorResultMessage();

		if (ex instanceof YitunException) {
			//自定义异常
			YitunException re = (YitunException)ex;
			result.addError(String.valueOf(re.getCode()), re.getMsg());
		} else if (ex instanceof HttpRequestMethodNotSupportedException) {
			//请求方法异常
			logErr(ex);
			result.addError(ExceptionEnum.HTTP_METHOD_NOT_SUPPORT.getCode().toString(), ExceptionEnum.HTTP_METHOD_NOT_SUPPORT.getMsg());
		} else if (ex instanceof MethodArgumentNotValidException) {
			//参数校验失败的异常
			logErr(ex);
			MethodArgumentNotValidException me = (MethodArgumentNotValidException)ex;
			List<ObjectError> allErrors = me.getBindingResult().getAllErrors();
			StringBuilder stringBuffer = new StringBuilder();
			for (ObjectError allError : allErrors) {
				stringBuffer.append(allError.getDefaultMessage()).append(";");
			}
			result.addError("-100", stringBuffer.toString());
		} else if (ex instanceof HttpMessageNotReadableException) {
			//http body参数无法读取转换
			logErr(ex);
			result.addError(ExceptionEnum.HTTP_BODY_NOT_READABLE.getCode().toString(), ExceptionEnum.HTTP_BODY_NOT_READABLE.getMsg());
		} else if (ex instanceof BadSqlGrammarException) {
			//sql语法错误
			logErr(ex);
			result.addError(ExceptionEnum.MYSQL_SQL_GRAMMAR_ERROR.getCode().toString(), ExceptionEnum.MYSQL_SQL_GRAMMAR_ERROR.getMsg());
		} else if (ex instanceof MissingServletRequestParameterException) {
			//服务器参数异常，一般是因为少传了参数导致
			logErr(ex);
			result.addError(ExceptionEnum.HTTP_PARAMETER_ERROR.getCode().toString(), ExceptionEnum.HTTP_PARAMETER_ERROR.getMsg());
		} else if (ex instanceof ConstraintViolationException) {
			//方法级别的参数校验异常
			logErr(ex);
			ConstraintViolationException ce = (ConstraintViolationException)ex;
			StringBuilder eMsg = new StringBuilder();
			for (ConstraintViolation<?> constraintViolation : ce.getConstraintViolations()) {
				eMsg.append(constraintViolation.getMessage()).append(";");
			}
			result.addError("-100", eMsg.toString());
		} else if (ex instanceof BindException) {
			//绑定的方法参数异常
			logErr(ex);
			BindException be = (BindException)ex;
			List<ObjectError> allErrors = be.getBindingResult().getAllErrors();
			StringBuilder stringBuffer = new StringBuilder();
			for (ObjectError allError : allErrors) {
				stringBuffer.append(allError.getDefaultMessage()).append(";");
			}
			result.addError("-100", stringBuffer.toString());
		} else if (ex instanceof MethodArgumentTypeMismatchException) {
			//方法参数无法转换异常，通常为定义一个Bol 类型的值，传过来的参数无法转换为bol  如null string int>2
			logErr(ex);
			result.addError(ExceptionEnum.METHOD_ARGUMENT_TYPE_MISMATCH_ERROR.getCode().toString(), ExceptionEnum.METHOD_ARGUMENT_TYPE_MISMATCH_ERROR.getMsg());
		} else {
			//全局异常
			logErr(ex);
			result.addError(ExceptionEnum.UNKNOW_ERROR.getCode().toString(),ExceptionEnum.UNKNOW_ERROR.getMsg());
		}

		response.setCharacterEncoding("UTF-8");
		ResponseUtil.putAllowOrigin(response);
		ResponseUtil.writer(response, YitunJsonUtil.objectToJson(result));
		return null;
	}

	/**
	 * 日志保存异常信息
	 *
	 * @param e
	 */
	private void logErr(Exception e) {
		log.error(e.getMessage(), e);
	}
}
